﻿using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Contracts.General;

namespace Wombat.Client.Core
{
    internal class ClientContext : IClientContext
    {
        private readonly IConfigurationService _configurationService;
        private IChannelFactory<IDataSubmissionService> _dataSubmissionServiceFactory;
        private IDataSubmissionService _dataSubmissionService;

        public ClientContext(IConfigurationService configurationService)
        {
            _configurationService = configurationService;
        }

        public void SendDataDouble<T>(T data) where T : ITimed<double?>
        {
            var proxy = GetDataSubmissionProxy();
            proxy.SubmitDataDouble(data.TagId, data.Time, data.Value);
        }

        private IDataSubmissionService GetDataSubmissionProxy()
        {
            return _dataSubmissionServiceFactory != null && _dataSubmissionServiceFactory.State == CommunicationState.Opened
                       ? _dataSubmissionService
                       : CreateDataSubmissionProxy();
        }

        private IDataSubmissionService CreateDataSubmissionProxy()
        {
            var bindingKey = _configurationService.GetConfigurationValue(ClientConfigurationLoader.Keys.WebServices,
                                                                         ClientConfigurationLoader.Keys.Binding);
            var binding = (Binding)new BasicHttpBinding();
            switch (bindingKey)
            {
                case "tcp":
                    binding = new NetTcpBinding(SecurityMode.None);
                    break;
                case "net":
                    binding = new NetHttpBinding(BasicHttpSecurityMode.None);
                    break;
            }
            var endpoint = new EndpointAddress(_configurationService.GetConfigurationValue(ClientConfigurationLoader.Keys.WebServices, ClientConfigurationLoader.Keys.BaseAddresss));
            try
            {
                _dataSubmissionServiceFactory = new ChannelFactory<IDataSubmissionService>(binding, endpoint);
                _dataSubmissionService = _dataSubmissionServiceFactory.CreateChannel(endpoint);
                if (_dataSubmissionServiceFactory.State == CommunicationState.Faulted)
                {
                    CloseDataSubmissionService();
                    throw new InvalidOperationException("Could not open channel to the server.");
                }
                if (_dataSubmissionServiceFactory.State != CommunicationState.Opened)
                    _dataSubmissionServiceFactory.Open();
                return _dataSubmissionService;
            }
            catch (Exception)
            {
                CloseDataSubmissionService();
                throw;
            }
        }

        public void Dispose()
        {
            CloseDataSubmissionService();
// ReSharper disable SuspiciousTypeConversion.Global
            ((IDisposable) _dataSubmissionServiceFactory).Dispose();
// ReSharper restore SuspiciousTypeConversion.Global
        }

        private void CloseDataSubmissionService()
        {
            if (_dataSubmissionServiceFactory.State == CommunicationState.Opened)
                _dataSubmissionServiceFactory.Close();
            else
                _dataSubmissionServiceFactory.Abort();
        }
    }
}